﻿namespace Edge.Utilities
{
    using System;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.IO;
    using System.Net;
    using System.Runtime.InteropServices;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;
    using mshtml;

    /// <summary>
    /// Contains various web-related utilities.
    /// </summary>
    public class WebUtilities
    {
        /// <summary>
        /// Interface to assist in rendering web page.
        /// </summary>
        [InterfaceType(1)]
        [Guid("3050F669-98B5-11CF-BB82-00AA00BDCE0B")]
        public interface IHTMLElementRender2
        {
            /// <summary>
            /// Interface to assist in rendering web page.
            /// </summary>
            /// <param name="hdc">Remote handle.</param>
            void DrawToDC(IntPtr hdc);

            /// <summary>
            /// Sets the document printer.
            /// </summary>
            /// <param name="bstrPrinterName">Printer name.</param>
            /// <param name="hdc">Remote handle.</param>
            void SetDocumentPrinter(string bstrPrinterName, ref _RemotableHandle hdc);
        }

        /// <summary>
        /// Retrieves the html contents from a url.
        /// </summary>
        /// <param name="url">The url to retrieve.</param>
        /// <returns>HTML string for a web page.</returns>
        public static string FetchHTML(string url)
        {
            WebClient client = new WebClient();

            return client.DownloadString(url);
        }

        /// <summary>
        /// Parses the title from an html string.
        /// </summary>
        /// <param name="html">HTML for which to retrieve the title.</param>
        /// <returns>Document title string.</returns>
        public static string FetchTitleFromHTML(string html)
        {
            string regex = @"(?<=<title.*>)([\s\S]*)(?=</title>)";
            
            Regex ex = new Regex(regex, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            
            return ex.Match(html).Value.Trim();
        }

        /// <summary>
        /// Retrieves the file name of the current page. 
        /// </summary>
        /// <returns>Name of the file rendering in the current context.</returns>
        public static string GetCurrentPageName()
        {
            string path = System.Web.HttpContext.Current.Request.Url.AbsolutePath;

            FileInfo fi = new FileInfo(path);

            return fi.Name;
        }

        #region WebPageBitmap

        /// <summary>
        /// Takes a snapshot of a web page.
        /// </summary>
        /// <example>
        ///     <code language="c#">
        ///         WebPageBitmap webBitmap = new WebPageBitmap(url, 400, 300, false);
        ///         webBitmap.Fetch();
        ///         Bitmap bitmap = webBitmap.GetBitmap(thumbwidth, thumbheight);
        ///     </code>
        /// </example>
        public class WebPageBitmap
        {
            /// <summary>
            /// Browser control used to assist in web page retrieval.
            /// </summary>
            private WebBrowser webBrowser;

            /// <summary>
            /// Url of the web page.
            /// </summary>
            private string url;

            /// <summary>
            /// Bitmap width;
            /// </summary>
            private int width;

            /// <summary>
            /// Bitmap height.
            /// </summary>
            private int height;

            /// <summary>
            /// Initializes a new instance of the WebPageBitmap class.
            /// </summary>
            /// <param name="url">Url to use when creating the bitmap.</param>
            /// <param name="width">Bitmap width.</param>
            /// <param name="height">Bitmap height.</param>
            /// <param name="scrollBarsEnabled">Include scrollbars in the bitmap.</param>
            public WebPageBitmap(string url, int width, int height, bool scrollBarsEnabled)
            {
                this.url = url;
                this.width = width;
                this.height = height;
                this.webBrowser = new WebBrowser();
                this.webBrowser.Size = new Size(width, height);
                this.webBrowser.ScrollBarsEnabled = scrollBarsEnabled;
            }

            /// <summary>
            /// Navigates to the url and waits until the web page is fully downloaded.
            /// </summary>
            public void Fetch()
            {
                this.webBrowser.Navigate(this.url);

                while (this.webBrowser.ReadyState != WebBrowserReadyState.Complete)
                {
                    Application.DoEvents();
                }
            }

            /// <summary>
            /// Creates a bitmap for the url of this instance.
            /// </summary>
            /// <param name="thumbwidth">Width of the bitmap.</param>
            /// <param name="thumbheight">Height of the bitmap.</param>
            /// <returns>Bitmap of the webpage.</returns>
            public Bitmap GetBitmap(int thumbwidth, int thumbheight)
            {
                IHTMLDocument2 rawDoc = (IHTMLDocument2)this.webBrowser.Document.DomDocument;
                IHTMLElement rawBody = rawDoc.body;
                IHTMLElementRender2 render = (IHTMLElementRender2)rawBody;

                Bitmap bitmap = new Bitmap(this.width, this.height);
                Rectangle bitmapRect = new Rectangle(0, 0, this.width, this.height);
                this.webBrowser.DrawToBitmap(bitmap, bitmapRect);
                Graphics graphics = Graphics.FromImage(bitmap);
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

                IntPtr graphicshdc = graphics.GetHdc();
                render.DrawToDC(graphicshdc);

                graphics.ReleaseHdc(graphicshdc);
                graphics.Dispose();

                return this.ResizeBitmap(bitmap, thumbwidth, thumbheight);
            }

            /// <summary>
            /// Resizes a bitmap.
            /// </summary>
            /// <param name="bitmap">Bitmap to resize</param>
            /// <param name="width">Width to resize the bitmap to</param>
            /// <param name="height">Height to resize the bitmap to</param>
            /// <returns>A resized bitmap</returns>
            private Bitmap ResizeBitmap(Bitmap bitmap, int width, int height)
            {
                Bitmap output = new Bitmap(width, height);
                Rectangle r = new Rectangle(0, 0, width, height);
                Graphics g = Graphics.FromImage(output);

                g.CompositingQuality = CompositingQuality.HighQuality;
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage(bitmap, r);

                bitmap.Dispose();

                return output;
            }
        }

        #endregion
    }
}
